package com.lovo.shirodemo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lovo.shirodemo.dao.FunctionInfoDAO;
import com.lovo.shirodemo.model.FunctionInfoDO;
import com.lovo.shirodemo.model.dto.FunctionInfoDTO;
import com.lovo.shirodemo.model.dto.RoleDTO;
import com.lovo.shirodemo.service.FunctionInfoService;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author bdk
 * @since 2020-11-26
 */
@Service
public class FunctionInfoServiceImpl extends ServiceImpl<FunctionInfoDAO, FunctionInfoDO> implements FunctionInfoService {
    @Resource
    private FunctionInfoDAO functionInfoDAO;
    @Resource
    @Lazy
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Override
    public void saveFunction(FunctionInfoDTO functionInfoDTO) {
        FunctionInfoDO functionInfoDO = new FunctionInfoDO();
        BeanUtils.copyProperties(functionInfoDTO,functionInfoDO);
        functionInfoDAO.insert(functionInfoDO);
        try {
            updatePermission(shiroFilterFactoryBean);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<FunctionInfoDTO> findByRoleIds(List<RoleDTO> roleList) {
        List ids = new ArrayList();
        for(RoleDTO role : roleList){
            ids.add(role.getRoleId());
        }
        return functionInfoDAO.selectByRoleIds(ids);
    }

    @Override
    public Map<String, String> loadFilterChainDefinitionMap() {
        Map<String,String> filterChainMap = new LinkedHashMap<String,String>(16);

        //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问,先配置anon再配置authc。
//        filterChainMap.put("/login", "anon");
        filterChainMap.put("/users/login", "anon");
        filterChainMap.put("/users/register", "anon");
        filterChainMap.put("/swagger-ui.html", "anon");
        filterChainMap.put("/v2/api-docs", "anon");
        filterChainMap.put("/swagger-resources/**", "anon");
        filterChainMap.put("/webjars/**", "anon");
        filterChainMap.put("/configuration/**", "anon");
        List<FunctionInfoDO> functionInfoList = functionInfoDAO.selectList(null);
        // 组装过滤路径
        for(FunctionInfoDO functionInfoDO : functionInfoList){
            String url = functionInfoDO.getUrl();
            if(functionInfoDO.getMethod() != null && !"".equals(functionInfoDO.getMethod())){
                url += "==" + functionInfoDO.getMethod();
            }
            filterChainMap.put(url,"perms["+functionInfoDO.getFunctionName()+"]");
        }
        filterChainMap.put("/**", "authc");
        return filterChainMap;

    }

    @Override
    public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean) throws Exception {
        synchronized (this) {
            AbstractShiroFilter shiroFilter;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                throw new Exception("get ShiroFilter from shiroFilterFactoryBean error!");
            }
            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();

            // 清空拦截管理器中的存储
            manager.getFilterChains().clear();
            // 清空拦截工厂中的存储,如果不清空这里,还会把之前的带进去
            //            ps:如果仅仅是更新的话,可以根据这里的 map 遍历数据修改,重新整理好权限再一起添加
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            // 动态查询数据库中所有权限
            shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitionMap());
            // 重新构建生成拦截
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                manager.createChain(entry.getKey(), entry.getValue());
            }

        }
    }
}
